/*
 * Copyright 2020 www.mytijian.com All right reserved. This software is the
 * confidential and proprietary information of www.mytijian.com ("Confidential
 * Information"). You shall not disclose such Confidential Information and shall
 * use it only in accordance with the terms of the license agreement you entered
 * into with www.mytijian.com.
 */
package com.mytijian.task.executor;

import com.mytijian.base.exception.BizException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
import java.util.stream.Collectors;

public class GroupExecutorService {
    private static Logger logger = LoggerFactory.getLogger(GroupExecutorService.class);
    private static Map<String, ThreadPoolExecutor> groupExecutorServiceMap = new HashMap<>();
    private static String defaultGroupKey = "-1";
    private static ThreadPoolExecutor getByGroupKey(String groupKey) {
        ThreadPoolExecutor executorService = groupExecutorServiceMap.get(groupKey);
        if (executorService == null) {
            executorService = groupExecutorServiceMap.get(defaultGroupKey);
        }
        return executorService;
    }
    public static Future submit(String groupKey, Runnable runnable) {
        ExecutorService executorService = getByGroupKey(groupKey);
        return executorService.submit(runnable);
    }
    public static long getCapacity(String groupKey) {
        ThreadPoolExecutor threadPoolExecutor = getByGroupKey(groupKey);
        return threadPoolExecutor.getMaximumPoolSize();
    }


    public static void shutdown(String groupKey) {
        ExecutorService executorService = getByGroupKey(groupKey);
        executorService.shutdown();
    }
    public static boolean isShutdown(String groupKey) {
        ExecutorService executorService = getByGroupKey(groupKey);
        return executorService.isShutdown();
    }
    public static void shutdownAll() {
        groupExecutorServiceMap.forEach((groupKey, executorService) -> {
            executorService.shutdown();
        });
    }
    public synchronized static void modifyExecutor(GroupExecutorParam param) {
        Assert.notNull(param.getGroupKey(), "groupKey 不能为空");
        Assert.notNull(param.getCapacity(), "capacity 不能为空");
        Assert.notNull(param.getWorkThreads(),"workThreads不能为空");
        if (param.getCapacity() < param.getWorkThreads()) {
            throw new BizException("12", "workThreads 必须<= capacity");
        }
        if (groupExecutorServiceMap.get(param.getGroupKey()) == null) {
            throw new BizException("12", "groupKey = " + param.getGroupKey() + ",不存在");
        }
        ThreadPoolExecutor executor = groupExecutorServiceMap.get(param.getGroupKey());
        if (executor.getMaximumPoolSize() > param.getCapacity()) {
            throw new BizException("12", "capacity 只能调大");
        }
        if (executor.getCorePoolSize() > param.getWorkThreads()) {
            throw new BizException("12", "workThreas只能调大");
        }
        executor.setMaximumPoolSize(param.getCapacity());
        executor.setCorePoolSize(param.getWorkThreads());
    }
    public synchronized static void addGroupExecutor(GroupExecutorParam param) {
        Assert.notNull(param.getGroupKey(), "groupKey 不能为空");
        Assert.notNull(param.getCapacity(), "capacity 不能为空");
        Assert.notNull(param.getWorkThreads(),"workThreads不能为空");
        if (groupExecutorServiceMap.get(param.getGroupKey()) != null) {
            throw new BizException("12", "groupKey = " + param.getGroupKey() + ",已经存在");
        }
        groupExecutorServiceMap.put(param.getGroupKey(), newInstance(param));
    }
    public synchronized static void init(List<GroupExecutorParam> params) {
        if (!CollectionUtils.isEmpty(groupExecutorServiceMap)) {
            throw new BizException("1234", "groupExecutor已经初始化，无需再次初始化");
        }
        if (params.stream().map(GroupExecutorParam::getGroupKey).distinct().collect(Collectors.toList()).size() != params.size()) {
            throw new BizException("123", "请保证groupKey唯一");
        }
        for (GroupExecutorParam groupExecutorParam : params) {
            ThreadPoolExecutor executorService = newInstance(groupExecutorParam);
            String groupKey = groupExecutorParam.groupKey;
            if (groupKey == null) {
                groupKey = defaultGroupKey;
            }
            groupExecutorServiceMap.put(groupKey, executorService);
        }
    }
    private static ThreadPoolExecutor newInstance(GroupExecutorParam groupExecutorParam) {
        return new ThreadPoolExecutor(groupExecutorParam.workThreads, groupExecutorParam.capacity, 20L, TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(groupExecutorParam.capacity), new GroupThreadFactory("g=" + groupExecutorParam.getGroupKey()), new ThreadPoolExecutor.CallerRunsPolicy());
    }
    public static void main(String[] args) throws InterruptedException {
        GroupExecutorParam groupExecutorParam = new GroupExecutorParam(2,2,"1");
        ThreadPoolExecutor poolExecutor = newInstance(groupExecutorParam);
        for (int i = 0; i< 2;i++) {
            poolExecutor.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println(Thread.currentThread().getName());
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() +"结束");
                }
            });
        }
        poolExecutor.setMaximumPoolSize(3);
        poolExecutor.setCorePoolSize(3);
        poolExecutor.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() +"结束");
            }
        });
        Thread.sleep(5000);
    }
    public static class GroupExecutorParam {
        private Integer workThreads;
        private Integer capacity;
        /**
         * 唯一
         */
        private String groupKey;

        public GroupExecutorParam(Integer workThreads, Integer capacity, String groupKey) {
            this.workThreads = workThreads;
            this.capacity = capacity;
            this.groupKey = groupKey;
        }

        public Integer getWorkThreads() {
            return workThreads;
        }

        public Integer getCapacity() {
            return capacity;
        }

        public String getGroupKey() {
            return groupKey;
        }
    }
}
